﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Reflection;
using Autofac;
using System.Linq;

namespace SXICE.Core.Helpers
{
    /// <summary>
    /// 运行时帮助类
    /// </summary>
    public class RuntimeHelper
    {
        static RuntimeHelper()
        {
            nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace.Split('.').First();
        }

        #region 变量

        /// <summary>
        /// 默认文件夹路径
        /// </summary>
        private static readonly string defaultFolder = AppContext.BaseDirectory;
        /// <summary>
        /// 命名空间
        /// </summary>
        private static readonly string nameSpace = string.Empty;
        /// <summary>
        /// 容器创建者
        /// </summary>
        private static ContainerBuilder containerBuilder;
        /// <summary>
        /// IOC容器
        /// </summary>
        private static IContainer container;
        /// <summary>
        /// 已加载的程序集
        /// </summary>
        private static ConcurrentDictionary<string, Assembly> assemblies = new ConcurrentDictionary<string, Assembly>();
        /// <summary>
        /// IOC容器
        /// </summary>
        public static IContainer Container
        {
            get
            {
                if (null == container)
                    container = containerBuilder.Build();
                return container;
            }
        }

        #endregion

        #region 方法

        /// <summary>
        /// 设置容器
        /// </summary>
        /// <param name="builder">容器</param>
        public static void SetContainer(ContainerBuilder builder)
        {
            if (null == containerBuilder)
                containerBuilder = builder;
        }

        /// <summary>
        /// 获取程序集所有Type
        /// </summary>
        /// <param name="func">回调函数</param>
        private static void GetAssemblyTypes(Func<IEnumerable<Type>, bool> func)
        {
            foreach (var file in Directory.GetFiles(defaultFolder, nameSpace + ".*.dll"))
            {
                var assembly = assemblies.GetOrAdd(file, Assembly.LoadFrom(file));
                if (!func(assembly.GetTypes()))
                    return;
            }
        }

        /// <summary>
        /// 获取接口对象
        /// </summary>
        /// <typeparam name="T">接口泛型</typeparam>
        /// <param name="parameters">参数</param>
        /// <returns>对象</returns>
        public static T Resolve<T>(params object[] parameters)
        {
            if (Container?.IsRegistered<T>() ?? false)
            {
                PositionalParameter[] positionalParameters = null;
                if (null != parameters)
                {
                    positionalParameters = new PositionalParameter[parameters.Length];
                    for (int i = 0; i < parameters.Length; i++)
                        positionalParameters[i] = new PositionalParameter(i, parameters[i]);
                }
                return Container.Resolve<T>(positionalParameters);
            }
            else
            {
                var type = FindAllDerivedClass<T>();
                if (null != type)
                    return (T)Activator.CreateInstance(type, parameters);
                return default;
            }
        }

        /// <summary>
        /// 获取多个接口对象
        /// </summary>
        /// <typeparam name="T">接口泛型</typeparam>
        /// <param name="parameters">参数</param>
        /// <returns>对象</returns>
        public static List<T> Resolves<T>(params object[] parameters)
        {
            return FindAllDerivedClasses<T>().Select(t => (T)Activator.CreateInstance(t)).ToList();
        }

        /// <summary>
        /// 查找所有派生类
        /// </summary>
        /// <param name="parentType">父Type</param>
        /// <returns>所有派生类</returns>
        public static List<Type> FindAllDerivedClasses<T>()
        {
            var parentType = typeof(T);
            var all = new List<Type>();
            GetAssemblyTypes(types =>
            {
                foreach (Type type in types)
                    if (type.IsClass && !type.IsInterface && parentType.IsAssignableFrom(type))
                        all.Add(type);
                return true;
            });
            return all;
        }

        /// <summary>
        /// 查找派生类
        /// </summary>
        /// <param name="parentType">父Type</param>
        /// <returns>派生类</returns>
        public static Type FindAllDerivedClass<T>()
        {
            var parentType = typeof(T);
            Type objType = null;
            GetAssemblyTypes(types =>
            {
                foreach (Type type in types)
                    if (type.IsClass && !type.IsInterface && parentType.IsAssignableFrom(type))
                    {
                        objType = type;
                        return false;
                    }
                return true;
            });
            return objType;
        }

        #endregion
    }
}
